package references

import "jvmgo/ch10/instructions/base"
import "jvmgo/ch10/rtda"
import "jvmgo/ch10/rtda/heap"

// 设置实例字段变量
type PUT_FIELD struct {
    base.Index16Instruction
}

func (self *PUT_FIELD) Execute(frame *rtda.Frame) {
    currentMethod := frame.Method()
    currentClass := currentMethod.Class()
    cp := currentClass.ConstantPool()
    fieldRef := cp.GetConstant(self.Index).(*heap.FieldRef)
    field := fieldRef.ResolvedField()

    if field.IsStatic() {
        panic("java.lang.IncompatibleClassChangeError")
    }
    if field.IsFinal() {
        if currentClass != field.Class() || currentMethod.Name() != "<init>" {
            panic("java.lang.IllegalAccessError")
        }
    }

    descriptor := field.Descriptor()
    slotId := field.SlotId()
    stack := frame.OperandStack()

    switch descriptor[0] {
    case 'Z', 'B', 'C', 'S', 'I':
        val := stack.PopInt()
        ref := stack.PopRef()
        if ref == nil {
            panic("java.lang.NullPointerException")
        }
        ref.Fields().SetInt(slotId, val)
    case 'F':
        val := stack.PopFloat()
        ref := stack.PopRef()
        if ref == nil {
            panic("java.lang.NullPointerException")
        }
        ref.Fields().SetFloat(slotId, val)
    case 'J':
        val := stack.PopLong()
        ref := stack.PopRef()
        if ref == nil {
            panic("java.lang.NullPointerException")
        }
        ref.Fields().SetLong(slotId, val)
    case 'D':
        val := stack.PopDouble()
        ref := stack.PopRef()
        if ref == nil {
            panic("java.lang.NullPointerException")
        }
        ref.Fields().SetDouble(slotId, val)
    case 'L', '[':
        val := stack.PopRef()
        ref := stack.PopRef()
        if ref == nil {
            panic("java.lang.NullPointerException")
        }
        ref.Fields().SetRef(slotId, val)
    default:
    // todo
    }
}
